﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MyFIFO
{
    /// <summary>
    /// 队列
    /// </summary>
    [Serializable]
    public class MyMessageQueue<T> :
        ICollection<T>, IEnumerable<T>, IEnumerable, IEnumerator, IEnumerator<T>, IReadOnlyCollection<T>
    {
        /// <summary>
        /// 数组的容量
        /// </summary>
        public int Capacity { get; private set; }

        /// <summary>
        /// 数组的最小容量
        /// </summary>
        public int MinCapacity { get; private set; }

        /// <summary>
        /// 数组现在有多少个元素
        /// </summary>
        public int Count { get; private set; }

        public bool IsReadOnly => false;

        T IEnumerator<T>.Current => this.Dequeue();

        object IEnumerator.Current => this.Dequeue();

        /// <summary>
        /// 数组
        /// </summary>
        private T[] array;

        /// <summary>
        /// 第一个元素的位置
        /// </summary>
        private int first;

        /// <summary>
        /// 最后一个元素的位置
        /// </summary>
        private int last;


        public MyMessageQueue()
            : this(10)
        {
        }

        /// <summary>
        /// 构造
        /// </summary>
        /// <param name="capacity">初始容量的大小</param>
        public MyMessageQueue(int capacity)
        {
            array = new T[capacity];
            Capacity = capacity;
            MinCapacity = capacity;
        }

        /// <summary>
        /// 构造
        /// </summary>
        /// <param name="ienum">开始给队列添加元素，是一个迭代器</param>
        public MyMessageQueue(IEnumerable<T> ienum)
            : this(ienum.Count())
        {
            foreach (var item in ienum)
            {
                Enqueue(item);
            }
        }

        /// <summary>
        /// 移除并返回第一位元素
        /// </summary>
        /// <returns></returns>
        public T Dequeue()
        {
            if (Count == 0)
            {
                return default(T);
            }
             
            //当前容量比默认容量大才缩容
            if (Count <= Capacity / 4  &&  Capacity > MinCapacity)
            {
                ResetArray(Capacity / 2);
            }

            Count--;
            T temp = array[first];
            array[first] = default(T);
            first = ++first % Capacity;

            return temp;
        }


        public bool TryDequeue(out T result)
        {
            result = Dequeue();
            if (result == null)
            {
                return false;
            }
            return true;
        }


        /// <summary>
        /// 再尾部添加元素
        /// </summary>
        /// <param name="item">需要添加的元素</param>
        public void Enqueue(T item)
        {
            //扩容
            if (Count == Capacity)
            {
               
                ResetArray(Capacity * 2);
            }

            Count++;
            array[last] = item;
            last = ++last % Capacity;
        }

        /// <summary>
        /// 看一下第一个元素，不移除
        /// </summary>
        /// <returns></returns>

        public T Peek()
        {
            if (Count == 0)
            {
                return default(T);
            }
            return array[first];
        }

        /// <summary>
        /// 重置数组的大小容量
        /// </summary>
        /// <param name="capacity">新的数组的大小容量</param>
        private void ResetArray(int capacity)
        {
            if (capacity > this.Capacity)
            {
                Console.WriteLine($"扩容===={capacity}");
            }
            else
            {
                Console.WriteLine($"缩容===={capacity}");
            }

            T[] newArray = new T[capacity];
            if (Count > 0)
            {
                if (first < last)
                {
                    Array.Copy(array, first, newArray, 0, Count);
                }
                else
                {
                    int temp = this.Capacity - first;
                    Array.Copy(array, first, newArray, 0, temp);
                    Array.Copy(array, 0, newArray, temp, last);
                }
            }
            first = 0;
            last = Count;
            this.Capacity = capacity;
            array = newArray;
        }

        private void ThrowError(string message)
        {
            throw new ArgumentException(message);
        }

        void ICollection<T>.Add(T item)
        {
            Enqueue(item);
        }

        void ICollection<T>.Clear()
        {
            Array.Clear(array, 0, Capacity);
            first = 0;
            last = 0;
            Count = 0;
        }

        /// <summary>
        /// 是否包含这个元素
        /// </summary>
        /// <param name="item"></param>
        /// <returns></returns>
        public bool Contains(T item)
        {
            int tempFirst = first;
            for (int i = 0; i < Count; i++)
            {
                if (array[tempFirst].Equals(item))
                {
                    return true;
                }
                else
                {
                    tempFirst = ++tempFirst & Capacity;
                }
            }
            return false;
        }

        public void CopyTo(T[] array, int arrayIndex)
        {
            if (object.ReferenceEquals(array, null))
                ThrowError("复制到数组为空");
            else if (arrayIndex >= Capacity)
                ThrowError("开始复制的数组索引超出Array的大小");
            else if (arrayIndex < 0)
                ThrowError("开始复制的数组索引不能小于0");

            int tempFirst = first;
            for (int i = 0; i < Count; i++)
            {
                array[i] = this.array[tempFirst];
                tempFirst = ++tempFirst % Capacity;
            }
        }

        public bool Remove(T item)
        {
            ThrowError("队列不支持此方法");
            return false;
        }

        public IEnumerator<T> GetEnumerator()
        {
            return this;
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return this;
        }

        public void Dispose()
        {

        }

        public bool MoveNext()
        {
            return Count > 0;
        }

        public void Reset()
        {
        }
    }



    public static class MyQueueTest
    {

        public static void Test()
        {
            Stopwatch stopwatch1 = new Stopwatch();
            stopwatch1.Start();
            MyMessageQueue<MyMsg<int>> queue = new MyMessageQueue<MyMsg<int>>();//自己的集合

            for (int i = 0; i < 90; i++)
            {
                queue.Enqueue(MyMsg<int>.Msg(0, i));
            }

            while (true)
            {
                MyMsg<int> s = queue.Dequeue();

                if (s != null)
                {
                    Console.WriteLine("==========================");
                    Console.WriteLine(s.data);

                }
                Task.Delay(2000);
            }


        }


    }





}

